
//=======================================================================================
//
// アプリケーションクラス
//
//=======================================================================================
App = function(){
} ;

//=======================================================================================
//
// アプリケーションページクラス
//
//=======================================================================================
App.Page = function(){
    var thispage = null ;   // 現在のページオブジェクト　※各ページのJSファイルにて設定
    // ページ読込完了イベントハンドラ設定
    Ext.EventManager.addListener(window, "load", this.onDocLoaded, this, true) ;
    // キー押下イベントハンドラ設定
    Ext.EventManager.addListener(document, "keydown", this.onDocKeyDown, this, true) ;
    
} ;

App.Page.prototype = {
    dialogs : {},
    tabindexies : [] ,  // ページ内タブインデックスIDリスト
                            // ※ サブクラスにてオーバーライドすることで、Enter移動を実装
    /*==================================================
     * 関数名：onDocLoaded
     * 概　要：ドキュメントロードイベントハンドラ
     * 引　数：なし
     * 戻り値：なし
     ==================================================*/
    onDocLoaded : function(eventObject, target){
        this.fncComponentSetEvent() ;
    },
    
    /*==================================================
     * 関数名：fncComponentSetEvent
     * 概　要：コンポーネントにキーイベントを設定する。
     *       ：ENTERキーフォーカス移動の為の実装。
     * 引　数：なし
     * 戻り値：なし
     ==================================================*/
    fncComponentSetEvent : function(){
        for( var i=0 ; i<this.tabindexies.length ; i++ ){
            var cmp = Ext.getCmp( this.tabindexies[i] ) ;
            if( cmp == null ) continue ;
            
            cmp.addListener("specialKey", this.onCmpSpecialKey, this, true) ;
        }
    },

    /*==================================================
     * 関数名：fncRemoveNextFocusHandler
     * 概　要：コンポーネントのEnterキーフォーカス移動用ハンドラを削除。
     * 引　数：id       String                  コンポーネントID
     * 戻り値：なし
     ==================================================*/
    fncRemoveNextFocusHandler : function(id){
        var cmp = Ext.getCmp( id ) ;
        if( cmp ){
            cmp.removeListener("specialKey", this.onCmpSpecialKey, this, true) ;
        }
    },

    /*==================================================
     * 関数名：onDocKeyDown
     * 概　要：ドキュメント上のキー押下イベントハンドラ。
     *       ：ENTERキーフォーカス移動の為の実装。
     * 引　数：eventObject      Ext.EventObject         イベントオブジェクト
     *       ：target           Ext.Element             ターゲットエレメント
     * 戻り値：なし
     ==================================================*/
    onDocKeyDown : function(eventObject, target){

        if( eventObject.getKey() != Ext.EventObject.ENTER ) return ;
        var targetelm = Ext.get(eventObject.getTarget()) ;
        var targetid = targetelm.id ;

        if( targetid == null)   return ;
        var targetcmp = Ext.getCmp(targetid) ;
        if( targetcmp ) return ;

        var index = this.tabindexies.indexOf(targetid) ;
        if( index<0 ) return ;

        switch( targetelm.dom.tagName.toLowerCase() ){
            case 'input' :
                var type = targetelm.dom.type.toLowerCase() ;
                if( type == "submit" || type == "button" || type == "image" ){
                    return ;
                }
                break ;
            case 'img' :
                return ;
                break ;
            case 'a' :
                return ;
                break ;
        }
        
        eventObject.stopEvent() ;
        this.fncNextFocus.defer(50, this, [targetid]) ;          
    },
    
    /*==================================================
     * 関数名：onCmpSpecialKey
     * 概　要：コンポーネント特殊キー押下イベントハンドラ。
     *       ：ENTERキーフォーカス移動の為の実装。
     * 引　数：target           Ext.Component           コンポーネント
     *       ：eventObject      Ext.EventObject         イベントオブジェクト
     * 戻り値：なし
     ==================================================*/
    onCmpSpecialKey : function(target, eventObject){
        if( eventObject.getKey() != Ext.EventObject.ENTER ) return ;

        var targetid = target.getId() ;

        if( targetid == null)   return ;

        eventObject.stopEvent() ;
        if( typeof target.triggerBlur == "function" ){
            target.triggerBlur.createDelegate(target).call();
        }
        this.fncNextFocus.defer(50, this, [targetid]) ;          
    },
    
    /*==================================================
     * 関数名：fncValidDate
     * 概　要：日付文字列が日付として正当かチェックする
     * 引　数：str           String      日付文字列
     * 戻り値：bool
     ==================================================*/
    fncValidDate : function(str){
		var dateFormat = new DateFormat("yyyy-MM-dd");
		var date = dateFormat.parse(str);
		if (!date) {
			var dateFormat = new DateFormat("yyyy/MM/dd");
			var date = dateFormat.parse(str);
		}
		if (!date) {
			return false;
		}
		return true;
    },
    
    /*==================================================
     * 関数名：fncBackToForth
     * 概　要：二つの日付文字列前後をチェックする
     * 引　数：forthdate     String      前日付文字列
     *       ：backdate      String      後日付文字列
     * 戻り値：bool
     ==================================================*/
    fncBackToForth : function(forthdate, backdate){
		var dateFormat = new DateFormat("yyyy-MM-dd");
		var f_date = dateFormat.parse(forthdate);
		if (!f_date) {
			var dateFormat = new DateFormat("yyyy/MM/dd");
			var f_date = dateFormat.parse(forthdate);
		}
		if (!f_date) {
			return false;
		}
		var dateFormat = new DateFormat("yyyy-MM-dd");
		var b_date = dateFormat.parse(backdate);
		if (!b_date) {
			var dateFormat = new DateFormat("yyyy/MM/dd");
			var b_date = dateFormat.parse(backdate);
		}
		if (!b_date) {
			return false;
		}
		if (f_date > b_date) {
			return false;
		}
		return true;
    },
    
    /*==================================================
     * 関数名：fncValidDateTime
     * 概　要：日付文字列(時刻付)が日付として正当かチェックする
     * 引　数：str           String      日付文字列
     * 戻り値：bool
     ==================================================*/
    fncValidDateTime : function(str){
		var dateFormat = new DateFormat("yyyy-MM-dd HH:mm");
		var date = dateFormat.parse(str);
		if (!date) {
			var dateFormat = new DateFormat("yyyy/MM/dd HH:mm");
			var date = dateFormat.parse(str);
		}
		if (!date) {
			return false;
		}
		return true;
    },
    
    /*==================================================
     * 関数名：fncBackToForthDateTime
     * 概　要：二つの日付文字列(時刻付)前後をチェックする
     * 引　数：forthdate     String      前日付文字列
     *       ：backdate      String      後日付文字列
     * 戻り値：bool
     ==================================================*/
    fncBackToForthDateTime : function(forthdate, backdate){
		var dateFormat = new DateFormat("yyyy-MM-dd HH:mm");
		var f_date = dateFormat.parse(forthdate);
		if (!f_date) {
			var dateFormat = new DateFormat("yyyy/MM/dd HH:mm");
			var f_date = dateFormat.parse(forthdate);
		}
		if (!f_date) {
			return false;
		}
		var dateFormat = new DateFormat("yyyy-MM-dd HH:mm");
		var b_date = dateFormat.parse(backdate);
		if (!b_date) {
			var dateFormat = new DateFormat("yyyy/MM/dd HH:mm");
			var b_date = dateFormat.parse(backdate);
		}
		if (!b_date) {
			return false;
		}
		if (f_date > b_date) {
			return false;
		}
		return true;
    },
    
    /*==================================================
     * 関数名：fncNextFocus
     * 概　要：指定されたIDを持つエレメントの、次のタブインデックスにフォーカスを設定する
     * 引　数：id               String          Enterキー押下エレメントID
     * 戻り値：なし
     ==================================================*/
    fncNextFocus : function(id){
        var index = this.tabindexies.indexOf(id) ;
        if( index>=0 ){
            var nextindex = index+1 ;
            if( nextindex >= this.tabindexies.length ) nextindex=0 ;
            
            var nextid = this.tabindexies[nextindex] ;
            var nextelm = Ext.get(nextid) ;
            var nextcmp = Ext.getCmp(nextid) ;

            if( nextcmp ){
                nextcmp.focus() ;
            }
            else if( nextelm ){
                nextelm.focus() ;
            }
        }

    }
    
} ;

//=======================================================================================
//
// アプリケーションダイアログクラス
//
//=======================================================================================
App.ModalDialog = function( config ){

    //-----------------------------
    // スーパークラスのコンストラクタを実行
    //-----------------------------
    App.ModalDialog.superclass.constructor.call(this);
    //-----------------------------
    // 初期化パラメータ設定
    //-----------------------------
    if( config != null){
        Ext.apply(this, config);
    }
} ;

// App.Pageを継承
Ext.extend(App.ModalDialog, App.Page, {
	dialog         :null,           // ダイアログオブジェクト
	width          :450,            // ダイアログ幅
	height         :400,            // ダイアログ高さ
	container      :"",             // コンテナエレメントのID
	anim_target_id :null,           // 表示・消去時のアニメーションのベースとなるエレメント

    /*==================================================
     * 関数名：onDocLoaded
     * 概　要：ドキュメントロードイベントハンドラ
     * 引　数：なし
     * 戻り値：なし
     ==================================================*/
    onDocLoaded : function(eventObject, target){
	    //-----------------------------
        // スーパークラスの処理を実行
	    //-----------------------------
        App.ModalDialog.superclass.onDocLoaded.call(this, eventObject, target);
    },
    
    /*==================================================
     * 関数名：fncShowDialog
     * 概　要：ダイアログを表示する
     * 引　数：initparam    Hash    初期化パラメータハッシュ
     * 戻り値：なし
     ==================================================*/
    fncShowDialog : function ( config ){
        // 初期化パラメータ設定
        if( config != null){
            Ext.apply(this, config);
        }

        if( this.dialog == null ){
            // 初回のみダイアログオブジェクト生成
            this.fncCreateDialog() ;
            this.fncReset() ;
        }
        else{
            // 再表示時はリセット処理
            this.fncReset() ;
        }

        // anim_target_idが指定されている場合は、アニメーションターゲット指定
        var base_elm_dom = null ;
        if( this.anim_target_id != null ){        
            var base_elm = Ext.get(this.anim_target_id) ;
            base_elm_dom = base_elm.dom ;
        }
        else{
        }

	    //-----------------------------
        // ダイアログ表示
	    //-----------------------------
//        this.dialog.center() ;
        this.dialog.x = undefined  ;
        this.dialog.y = undefined  ;
       	this.dialog.show(base_elm_dom);

        return false ;
    },

    /*==================================================
     * 関数名：fncReset
     * 概　要：ダイアログ内容をリセットする（初期表示時、再表示時に呼び出される）
     * 引　数：なし
     * 戻り値：なし
     ==================================================*/
    fncReset: function(){
    },

    /*==================================================
     * 関数名：fncCreateDialog
     * 概　要：コンテナエレメントに対して、ダイアログオブジェクトを生成する
     *       ：（初期表示時に呼び出される）
     * 引　数：なし
     * 戻り値：なし
     ==================================================*/
    fncCreateDialog : function(){
        // ダイアログ生成
	    this.dialog = new Ext.Window({ 
            el : this.container ,
            modal:      true,
            width:      this.width,
            height:     this.height,
            shadow:     true,
            minWidth:   this.width,
            minHeight:  this.height,
            resizable:  false,
            closeAction:'hide'
		});
	    //-----------------------------
		// イベント設定(下記以外に必要なイベントは、サブクラスにて実装)
	    //-----------------------------
		this.dialog.addListener('beforehide', this.onBeforeHide, this, true);
		this.dialog.addListener('beforeshow', this.onBeforeShow, this, true);
		this.dialog.addListener('hide', this.onHide, this, true);
		this.dialog.addListener('keydown', this.onKeyDown, this, true);
		this.dialog.addListener('move', this.onMove, this, true);
		this.dialog.addListener('resize', this.onResize, this, true);
		this.dialog.addListener('show', this.onShow, this, true);
    },

    /*==================================================
     * 関数名：fncExecCallback
     * 概　要：コールバック関数が指定されていれば、それを呼び出す
     * 引　数：cb_name          string    コールバック種類文字列
     * 戻り値：なし
     ==================================================*/
    fncExecCallback : function( cb_name ){
        if( this[cb_name] == null )    return false ;
        
        // 指定されているコールバック関数の配列を取得
        var target_callback = this[cb_name] ;
    
        // コールバック関数を順に実施
        if( target_callback != null && target_callback.length > 0 ){
            for( var findex=0 ; findex<target_callback.length ; findex++ ){
                var cb_func = target_callback[findex] ;
                cb_func.call() ;
            }
        }
    },

    /*==================================================
     * 関数名：fncGetAttribute
     * 概　要：属性値を取得する
     * 引　数：attr_name          string    属性名
     * 戻り値：属性値
     ==================================================*/
    fncGetAttribute : function( attr_name ){
        switch( attr_name ){
            case 'width' :
            case 'height' :
            case 'container' :
            case 'anim_target_id' :
                return this[attr_name] ;
                break ;
            default :
                return false ;
                break ;
        }
    },

    /*==================================================
     * 関数名：onBeforeHide
     * 概　要：ダイアログ非表示前イベント
     * 引　数：dlg                        Ext.BasicDialog           ダイアログオブジェクト
     * 戻り値：なし
     ==================================================*/
    onBeforeHide : function ( dlg ){
    },

    /*==================================================
     * 関数名：__onBeforeShow
     * 概　要：ダイアログ表示前イベント
     * 引　数：dlg                        Ext.BasicDialog           ダイアログオブジェクト
     * 戻り値：なし
     ==================================================*/
    onBeforeShow : function ( dlg ){
    },

    /*==================================================
     * 関数名：onHide
     * 概　要：ダイアログ非表示イベント
     * 引　数：dlg                        Ext.BasicDialog           ダイアログオブジェクト
     * 戻り値：なし
     ==================================================*/
    onHide : function ( dlg ){
    },

    /*==================================================
     * 関数名：onKeyDown
     * 概　要：キー押下イベント
     * 引　数：dlg                        Ext.BasicDialog           ダイアログオブジェクト
     *         e                          Ext.EventObject           イベントオブジェクト
     * 戻り値：なし
     ==================================================*/
    onKeyDown : function ( dlg, e ){
    },

    /*==================================================
     * 関数名：onMove
     * 概　要：ダイアログ移動イベント
     * 引　数：dlg                        Ext.BasicDialog           ダイアログオブジェクト
     *         x                          Number                    X座標値
     *         y                          Number                    Y座標値
     * 戻り値：なし
     ==================================================*/
    onMove : function ( dlg, x, y  ){
    },

    /*==================================================
     * 関数名：onResize
     * 概　要：ダイアログリサイズイベント
     * 引　数：dlg                        Ext.BasicDialog           ダイアログオブジェクト
     *         width                      Number                    幅
     *         height                     Number                    高さ
     * 戻り値：なし
     ==================================================*/
    onResize : function ( dlg, width, height  ){
    },

    /*==================================================
     * 関数名：onShow
     * 概　要：ダイアログ表示イベント
     * 引　数：dlg                        Ext.BasicDialog           ダイアログオブジェクト
     * 戻り値：なし
     ==================================================*/
    onShow : function ( dlg ){
    }
    
}) ;


/*
--------------------------------------------------------
dateformat.js - Simple date formatter
Version 1.1 (Update 2008/04/02)

Copyright (c) 2007-2008 onozaty (http://www.enjoyxstudy.com)

Released under an MIT-style license.

For details, see the web site:
 http://www.enjoyxstudy.com/javascript/dateformat/

--------------------------------------------------------
patterns
y : Year         ex. "yyyy" -> "2007", "yy" -> "07"
M : Month        ex. "MM" -> "05" "12", "M" -> "5" "12"
d : Day          ex. "dd" -> "09" "30", "d" -> "9" "30"
H : Hour (0-23)  ex. "HH" -> "00" "23", "H" -> "0" "23"
m : Minute       ex. "mm" -> "01" "59", "m" -> "1" "59"
s : Second       ex. "ss" -> "00" "59", "H" -> "0" "59"
S : Millisecond  ex. "SSS" -> "000" "012" "999", 
                     "SS" -> "00" "12" "999", "S" -> "0" "12" "999"

Text can be quoted using single quotes (') to avoid interpretation.
"''" represents a single quote. 


Useing..

 var fmt = new DateFormat("yyyy/MM/dd HH:mm:ss SSS");

 var str = fmt.format(new Date()); // "2007/05/10 12:21:19 002"
 var date = fmt.parse("2007/05/10 12:21:19 002"); // return Date object

--------------------------------------------------------
*/

var DateFormat = function(pattern) {
  this._init(pattern);
};

DateFormat.prototype = {
  _init: function(pattern) {

    this.pattern = pattern;
    this._patterns = [];

    for (var i = 0; i < pattern.length; i++) {
      var ch = pattern.charAt(i);
      if (this._patterns.length == 0) {
        this._patterns[0] = ch;
      } else {
        var index = this._patterns.length - 1;
        if (this._patterns[index].charAt(0) == "'") {
          if (this._patterns[index].length == 1 
             || this._patterns[index].charAt(this._patterns[index].length - 1) != "'") {
            this._patterns[index] += ch;
          } else {
            this._patterns[index + 1] = ch;
          }
        } else if (this._patterns[index].charAt(0) == ch) {
          this._patterns[index] += ch;
        } else {
          this._patterns[index + 1] = ch;
        }
      }
    }
  },

  format: function(date) {

    var result = [];
    for (var i = 0; i < this._patterns.length; i++) {
      result[i] = this._formatWord(date, this._patterns[i]);
    }
    return result.join('');
  },
  _formatWord: function(date, pattern) {

    var formatter = this._formatter[pattern.charAt(0)];
    if (formatter) {
      return formatter.apply(this, [date, pattern]);
    } else {
      return pattern;
    }
  },
  _formatter: {
    "y": function(date, pattern) {
      // Year
      var year = String(date.getFullYear());
      if (pattern.length <= 2) {
        year = year.substring(2, 4);
      } else {
        year = this._zeroPadding(year, pattern.length);
      }
      return year;
    },
    "M": function(date, pattern) {
      // Month in year
      return this._zeroPadding(String(date.getMonth() + 1), pattern.length);
    },
    "d": function(date, pattern) {
      // Day in month
      return this._zeroPadding(String(date.getDate()), pattern.length);
    },
    "H": function(date, pattern) {
      // Hour in day (0-23)
      return this._zeroPadding(String(date.getHours()), pattern.length);
    },
    "m": function(date, pattern) {
      // Minute in hour
      return this._zeroPadding(String(date.getMinutes()), pattern.length);
    },
    "s": function(date, pattern) {
      // Second in minute
      return this._zeroPadding(String(date.getSeconds()), pattern.length);
    },
    "S": function(date, pattern) {
      // Millisecond
      return this._zeroPadding(String(date.getMilliseconds()), pattern.length);
    },
    "'": function(date, pattern) {
      // escape
      if (pattern == "''") {
        return "'";
      } else {
        return pattern.replace(/'/g, '');
      }
    }
  },

  _zeroPadding: function(str, length) {
    if (str.length >= length) {
      return str;
    }

    return new Array(length - str.length + 1).join("0") + str;
  },


  /// Parser ///
  parse: function(text) {

    if (typeof text != 'string' || text == '') return null;

    var result = {year: 1970, month: 1, day: 1, hour: 0, min: 0, sec: 0, msec: 0};

    for (var i = 0; i < this._patterns.length; i++) {
       if (text == '') return null; // parse error!!
       text = this._parseWord(text, this._patterns[i], result);
       if (text === null) return null; // parse error!!
    }
    if (text != '') return null; // parse error!!

    return new Date(
                result.year,
                result.month - 1,
                result.day,
                result.hour,
                result.min,
                result.sec,
                result.msec);
  },
  _parseWord: function(text, pattern, result) {

    var parser = this._parser[pattern.charAt(0)];
    if (parser) {
      return parser.apply(this, [text, pattern, result]);
    } else {
      if (text.indexOf(pattern) != 0) {
        return null;
      } else {
        return text.substring(pattern.length);
      }
    }
  },
  _parser: {
    "y": function(text, pattern, result) {
      // Year
      var year;
      if (pattern.length <= 2) {
        year = text.substring(0, 2);
        year = year < 70 ? '20' + year : '19' + year;
        text = text.substring(2);
      } else {
        var length = (pattern.length == 3) ? 4 : pattern.length;
        year = text.substring(0, length);
        text = text.substring(length);
      }
      if (!this._isNumber(year)) return null; // error
      result.year = parseInt(year, 10);
      return text;
    },
    "M": function(text, pattern, result) {
      // Month in year
      var month;
      if (pattern.length == 1 && text.length > 1
          && text.substring(0, 2).match(/1[0-2]/) != null) {
        month = text.substring(0, 2);
        text  = text.substring(2);
      } else {
        month = text.substring(0, pattern.length);
        text  = text.substring(pattern.length);
      }
      if (!this._isNumber(month)) return null; // error
      result.month = parseInt(month, 10);
      return text;
    },
    "d": function(text, pattern, result) {
      // Day in month
      var day;
      if (pattern.length == 1 && text.length > 1 
          && text.substring(0, 2).match(/1[0-9]|2[0-9]|3[0-1]/) != null) {
        day  = text.substring(0, 2);
        text = text.substring(2);
      } else {
        day  = text.substring(0, pattern.length);
        text = text.substring(pattern.length);
      }
      if (!this._isNumber(day)) return null; // error
      result.day = parseInt(day, 10);
      return text;
    },
    "H": function(text, pattern, result) {
      // Hour in day (0-23)
      var hour;
      if (pattern.length == 1 && text.length > 1
          && text.substring(0, 2).match(/1[0-9]|2[0-3]/) != null) {
        hour = text.substring(0, 2);
        text = text.substring(2);
      } else {
        hour = text.substring(0, pattern.length);
        text = text.substring(pattern.length);
      }
      if (!this._isNumber(hour)) return null; // error
      result.hour = parseInt(hour, 10);
      return text;
    },
    "m": function(text, pattern, result) {
      // Minute in hour
      var min;
      if (pattern.length == 1 && text.length > 1
          && text.substring(0, 2).match(/[1-5][0-9]/) != null) {
        min  = text.substring(0, 2);
        text = text.substring(2);
      } else {
        min  = text.substring(0, pattern.length);
        text = text.substring(pattern.length);
      }
      if (!this._isNumber(min)) return null; // error
      result.min = parseInt(min, 10);
      return text;
    },
    "s": function(text, pattern, result) {
      // Second in minute
      var sec;
      if (pattern.length == 1 && text.length > 1
          && text.substring(0, 2).match(/[1-5][0-9]/) != null) {
        sec  = text.substring(0, 2);
        text = text.substring(2);
      } else {
        sec  = text.substring(0, pattern.length);
        text = text.substring(pattern.length);
      }
      if (!this._isNumber(sec)) return null; // error
      result.sec = parseInt(sec, 10);
      return text;
    },
    "S": function(text, pattern, result) {
      // Millimsecond
      var msec;
      if (pattern.length == 1 || pattern.length == 2) {
        if (text.length > 2 && text.substring(0, 3).match(/[1-9][0-9][0-9]/) != null) {
          msec = text.substring(0, 3);
          text = text.substring(3);
        } else if (text.length > 1 && text.substring(0, 2).match(/[1-9][0-9]/) != null) {
          msec = text.substring(0, 2);
          text = text.substring(2);
        } else {
          msec = text.substring(0, pattern.length);
          text = text.substring(pattern.length);
        }
      } else {
        msec = text.substring(0, pattern.length);
        text = text.substring(pattern.length);
      }
      if (!this._isNumber(msec)) return null; // error
      result.msec = parseInt(msec, 10);
      return text;
    },
    "'": function(text, pattern, result) {
      // escape
      if (pattern == "''") {
        pattern = "'";
      } else {
        pattern = pattern.replace(/'/g, '');
      }
      if (text.indexOf(pattern) != 0) {
        return null; // error
      } else {
        return text.substring(pattern.length);
      }
    }
  },

  _isNumber: function(str) {
    return /^[0-9]*$/.test(str);
  }
}
